﻿using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace FreshMeat.Storage
{
   /// <summary>
   /// Defines a file system.
   /// </summary>
   public interface IFileSystem
   {
      /// <summary>
      /// Creates a folder.
      /// If the folder already exists, this does nothing.
      /// </summary>
      /// <param name="path">The path to the folder.</param>
      void CreateFolder(string path);

      /// <summary>
      /// Creates a folder.
      /// If the folder already exists, this does nothing.
      /// </summary>
      /// <param name="path">The path to the folder.</param>
      Task CreateFolderAsync(string path);

      /// <summary>
      /// Deletes a folder.
      /// If the folder does not exist, this does nothing.
      /// </summary>
      /// <param name="path">The path to the folder.</param>
      /// <returns>True if the file was deleted; false if the file did not exist.</returns>
      bool DeleteFolder(string path);

      /// <summary>
      /// Deletes a folder.
      /// If the folder does not exist, this does nothing.
      /// </summary>
      /// <param name="path">The path to the folder.</param>
      /// <returns>True if the file was deleted; false if the file did not exist.</returns>
      Task<bool> DeleteFolderAsync(string path);

      /// <summary>
      /// Determines whether a folder exists.
      /// </summary>
      /// <param name="path">The path to the folder.</param>
      bool FolderExists(string path);

      /// <summary>
      /// Determines whether a folder exists.
      /// </summary>
      /// <param name="path">The path to the folder.</param>
      Task<bool> FolderExistsAsync(string path);

      /// <summary>
      /// Enumerates the files in a folder.
      /// </summary>
      /// <param name="path">The path to the folder.</param>
      /// <param name="searchPattern">The search pattern, e.g. "*.txt" or "Doc?.txt.</param>
      /// <param name="recurse">True to recurse into subfolders, false to only check the specified folder.</param>
      /// <returns>Paths to files which match the search pattern.</returns>
      IEnumerable<string> EnumerateFiles(string path, string searchPattern, bool recurse);

      /// <summary>
      /// Enumerates the files in a folder.
      /// </summary>
      /// <param name="path">The path to the folder.</param>
      /// <param name="searchPattern">The search pattern, e.g. "*.txt" or "Doc?.txt.</param>
      /// <param name="recurse">True to recurse into subfolders, false to only check the specified folder.</param>
      /// <returns>Paths to files which match the search pattern.</returns>
      Task<IEnumerable<string>> EnumerateFilesAsync(string path, string searchPattern, bool recurse);

      /// <summary>
      /// Moves and/or renames a file.
      /// An exception will be thrown if the destination file already exists.
      /// </summary>
      /// <param name="sourcePath">The path to the source file.</param>
      /// <param name="destinationPath">The path to the destination file.</param>
      void MoveFile(string sourcePath, string destinationPath);

      /// <summary>
      /// Moves and/or renames a file.
      /// An exception will be thrown if the destination file already exists.
      /// </summary>
      /// <param name="sourcePath">The path to the source file.</param>
      /// <param name="destinationPath">The path to the destination file.</param>
      Task MoveFileAsync(string sourcePath, string destinationPath);

      /// <summary>
      /// Determines whether a file exists.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      bool FileExists(string path);

      /// <summary>
      /// Determines whether a file exists.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      Task<bool> FileExistsAsync(string path);

      /// <summary>
      /// Deletes a file.
      /// If the file does not exist, this does nothing.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <returns>True if the file was deleted; false if the file did not exist.</returns>
      bool DeleteFile(string path);

      /// <summary>
      /// Deletes a file.
      /// If the file does not exist, this does nothing.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <returns>True if the file was deleted; false if the file did not exist.</returns>
      Task<bool> DeleteFileAsync(string path);

      /// <summary>
      /// Writes text to a file.
      /// If the file does not exist then it's created; if it does exist then it's overwritten.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <param name="text">The contents of the file.</param>
      void WriteAllText(string path, string text);

      /// <summary>
      /// Writes text to a file.
      /// If the file does not exist then it's created; if it does exist then it's overwritten.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <param name="text">The contents of the file.</param>
      Task WriteAllTextAsync(string path, string text);

      /// <summary>
      /// Reads the contents of an existing file as text.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <returns>The contents of the file.</returns>
      string ReadAllText(string path);

      /// <summary>
      /// Reads the contents of an existing file as text.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <returns>The contents of the file.</returns>
      Task<string> ReadAllTextAsync(string path);

      /// <summary>
      /// Opens an existing file for reading.
      /// The sharing mode is read-only.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <param name="mode">Open mode.</param>
      /// <param name="share">Share mode.</param>
      /// <returns>Stream that can be read from but not written to; must be disposed to close file.</returns>
      Stream OpenForRead(string path, OpenMode mode = OpenMode.Open, OpenShare share = OpenShare.Read);

      /// <summary>
      /// Opens an existing file for reading.
      /// The sharing mode is read-only.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <param name="mode">Open mode.</param>
      /// <param name="share">Share mode.</param>
      /// <returns>Stream that can be read from but not written to; must be disposed to close file.</returns>
      Task<Stream> OpenForReadAsync(string path, OpenMode mode = OpenMode.Open, OpenShare share = OpenShare.Read);

      /// <summary>
      /// Opens a file for writing; if the file does not exist, it is created.
      /// The sharing mode is none.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <param name="mode">Open mode.</param>
      /// <param name="share">Share mode.</param>
      /// <returns>Stream that can be read from and written to; must be disposed to close file.</returns>
      Stream OpenForWrite(string path, OpenMode mode = OpenMode.OpenOrCreate, OpenShare share = OpenShare.None);

      /// <summary>
      /// Opens a file for writing; if the file does not exist, it is created.
      /// The sharing mode is none.
      /// </summary>
      /// <param name="path">The path to the file.</param>
      /// <param name="mode">Open mode.</param>
      /// <param name="share">Share mode.</param>
      /// <returns>Stream that can be read from and written to; must be disposed to close file.</returns>
      Task<Stream> OpenForWriteAsync(string path, OpenMode mode = OpenMode.OpenOrCreate, OpenShare share = OpenShare.None);
   }
}